#include "e2d/ui/Utils.h"

ModelImporter e2d::Utils::m_ModelImporter;
AudioImporter e2d::Utils::m_AudioImporter;
TextureImporter e2d::Utils::m_TextureImporter;
ShaderImporter e2d::Utils::m_ShaderImporter;
CSharpImpoter e2d::Utils::m_CSharpImporter;

ModelLoader e2d::Utils::m_ModelLoader;
AudioLoader e2d::Utils::m_AudioLoader;
TextureLoader e2d::Utils::m_TextureLoader;
CSharpLoader e2d::Utils::m_CSharpLoader;
ActorLoader e2d::Utils::m_ActorLoader;
ShaderLoader e2d::Utils::m_ShaderLoader;
EffectsLoader e2d::Utils::m_EffectsLoader;

e2d::PrefebImporter e2d::Utils::m_PrefebImporter;
e2d::PrefebLoader e2d::Utils::m_PrefebLoader;

e2d::Inst e2d::Utils::m_Inst;
e2d::GameManager e2d::Utils::m_GameManager;
std::string e2d::Utils::m_CachePath = (fs::path(sysx::System::GetHome()) / (".e2d/cache")).string();
fxcc::Cache e2d::Utils::m_Cache;


void e2d::Utils::InitGameManager()
{
    m_GameManager.Init();
}

bool e2d::Utils::ImportDirectory(const fxcc::Dir& dir)
{
    std::thread TH_MODEL_IMPORT([&]() {
        m_ModelImporter.ImportDir(dir, true);
        });
    std::thread TH_AUDIO_IMPORT([&]() {
        m_AudioImporter.ImportDir(dir, true);
        });
    //std::thread TH_TEXTURE_IMPORT([&]() {
    //    m_TextureImporter.ImportDir(dir, true);
    //    });

    std::thread TH_CSHARP_IMPORT([&]() {
        m_CSharpImporter.ImportDir(dir, true);
        });
    std::thread TH_PREFEB_IMPORT([&]() {
        m_PrefebImporter.ImportDir(dir, true);
        });

    //std::thread TH_SHADER_IMPORT([&]() {
    //    m_ShaderImporter.ImportDir(dir, true);
    //    });

    auto _Import_Texture_Func = [&]() {
        m_TextureImporter.ImportDir(dir, true);
        };
    _Import_Texture_Func();

    // Threads join
    TH_MODEL_IMPORT.join();
    TH_AUDIO_IMPORT.join();
    //TH_TEXTURE_IMPORT.join();
    TH_CSHARP_IMPORT.join();
    TH_PREFEB_IMPORT.join();
    //TH_SHADER_IMPORT.join();

    ztclog::info("all resource has been load");
    return true;
}

bool e2d::Utils::InitLoader()
{
    ztclog::info("init load");
    
    if (!m_AudioLoader.InitWorld())
    {
        ztclog::warn("Failed load the audio loader");
        return false;
    }

    if (!m_CSharpLoader.InitMono())
    {
        ztclog::info("Failed load mono system");
        return false;
    }

    return true;
}


bool e2d::Utils::LoadDirectory(const fxcc::Dir& dir)
{
    m_AudioLoader.LoadDirectory(dir);
    m_ModelLoader.LoadDirectory(dir);
    m_TextureLoader.LoadDirectory(dir);
    m_CSharpLoader.LoadDirectory(dir);

    
    return true;
}

bool e2d::Utils::LoadShaderDir(const fxcc::Dir& dir)
{
    m_ShaderLoader.LoadDirectory(dir);
    return true;
}

bool e2d::Utils::LoadRealMaterial(const fxcc::Dir& dir)
{
    m_ModelLoader.LoadDirectory(dir);
    return true;
}

bool e2d::Utils::LoadFile(const fxcc::File& file)
{
    const std::string suffix = file.m_Suffix;

    switch (file.m_FileType)
    {
    case fxcc::_Skinned_:
    case fxcc::_Mesh_:
    case fxcc::_Anim_:
    case fxcc::_Bone_:
    case fxcc::_Mat_:
        return m_ModelLoader.LoadFile(file);
    case fxcc::_Ogg_:
        return m_AudioLoader.LoadFile(file);
    case fxcc::_DDS_:
        return m_TextureLoader.LoadDDSFile(file);
    case fxcc::_Actor_:
        return m_ActorLoader.LoadFile(file);
    case fxcc::_DLL_:
        return m_CSharpLoader.LoadFile(file);
    case fxcc::_Prefeb_:
        return m_PrefebLoader.LoadFile(file);
    default:
        return false;
    }

    return true;
}


bool e2d::Utils::SaveMetaCache()
{
    FXCC_FAILED(ModelImporter::SaveCache());
    FXCC_FAILED(AudioImporter::SaveCache());
    FXCC_FAILED(TextureImporter::SaveCache());
    FXCC_FAILED(CSharpImpoter::SaveCache());
    FXCC_FAILED(PrefebImporter::SaveCache());
    FXCC_FAILED(ShaderImporter::SaveCache());

    return true;
}

bool e2d::Utils::LoadMetaCache()
{
    FXCC_FAILED(ModelImporter::LoadCache());
    FXCC_FAILED(AudioImporter::LoadCache());
    FXCC_FAILED(TextureImporter::LoadCache());
    FXCC_FAILED(CSharpImpoter::LoadCache());
    FXCC_FAILED(PrefebImporter::LoadCache());
    FXCC_FAILED(ShaderImporter::LoadCache());

    return true;
}

void e2d::Utils::OnDestroy()
{
    m_GameManager.OnDestory();

}

bool e2d::Utils::LoadLastInstance()
{
    fxcc::yml::Serializer m_YamlSerialzier;

    bool loadCache = m_YamlSerialzier.DecodePath<fxcc::Cache>(m_CachePath, e2d::Utils::m_Cache);

    bool flag1 = loadCache && fs::exists(m_Cache.m_LastOpen);

    if (flag1)
    {
        bool loadLastOpen = m_YamlSerialzier.DecodePath<e2d::Inst>(m_Cache.m_LastOpen, e2d::Utils::m_Inst);

        if (loadLastOpen)
        {
            m_Inst.m_Scene->OnLoad();

        }
    }

    return true;
}

void e2d::Utils::OnLoadData(const std::string& newPath)
{
    auto& sg = e2d::State::Inst();

    //std::string newPath = m_Inst.m_FileHeader.GetFullPath();
    m_Cache.AddRecentPath(newPath);
    m_Inst = {};

    fxcc::yml::Serializer m_YamlSerialzier;
    bool flag = m_YamlSerialzier.DecodePath<e2d::Inst>(newPath, m_Inst);

    if (flag)
    {
        m_Inst.OnLoad();
    }
}

void e2d::Utils::OnSaveData()
{
    auto m_Timer = m_GameManager.m_Timer;
    static float m_LastSaveTime{ 0.f };
    static float m_SaveInterval{ 0.5f };

    if (m_Timer->CurrentTime() - m_LastSaveTime < m_SaveInterval)
    {
        return;
    }

    ztclog::info("[data] save the data");

    static fxcc::yml::Serializer m_YamlSerialzier;
    m_Cache.m_LastOpen = m_Inst.m_FileHeader.GetFullPath();
    m_Cache.AddRecentPath(m_Cache.m_LastOpen);

    m_YamlSerialzier.EncodePath<fxcc::Cache>(m_CachePath, m_Cache);
    m_YamlSerialzier.EncodePath<e2d::Inst>(m_Inst.m_FileHeader.GetFullPath(), m_Inst);

    e2d::Utils::SaveMetaCache();

    m_LastSaveTime = m_Timer->CurrentTime();

}


void e2d::Utils::SetSceneFromInst()
{
    m_GameManager.SetScene(m_Inst.m_Scene);
    m_GameManager.OnLoad();

}

void e2d::Utils::OnRenderFrame()
{
    m_GameManager.OnRender();
    m_GameManager.OnRenderRuntime();
}

void e2d::Utils::NewInstance()
{
    m_Inst = {};
}

void e2d::Utils::InitAudioWorld()
{
    e2d::AudioWorld::Inst().TryInit();
}

